package cn.stylefeng.guns.modular.fin.service;

import cn.hutool.core.util.StrUtil;
import cn.stylefeng.guns.core.exceptions.UpdateDataException;
import cn.stylefeng.guns.modular.app.dto.ApiMiningCurrencyCoinDto;
import cn.stylefeng.guns.modular.base.state.Constant;
import cn.stylefeng.guns.modular.base.state.ProConst;
import cn.stylefeng.guns.modular.base.state.F;
import cn.stylefeng.guns.modular.chain.entity.Transfer;
import cn.stylefeng.guns.modular.fin.mapper.FinMiningMapper;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import cn.stylefeng.roses.core.reqres.response.SuccessResponseData;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.stylefeng.guns.core.common.page.LayuiPageFactory;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.stylefeng.guns.modular.fin.entity.Currency;
import cn.stylefeng.guns.modular.fin.mapper.CurrencyMapper;

import javax.annotation.Resource;

/**
 * 币币账户Service
 *
 * @author yaying.liu
 * @Date 2020-03-12 19:10:50
 */
@Service
public class CurrencyService extends ServiceImpl<CurrencyMapper, Currency> {
    @Resource
    private FinMiningMapper finMiningMapper;

    /**
     * 查询币币账户
     */
    public Page<Map<String, Object>> selectByCondition(Double minPrice, Double maxPrice, String condition, Long memberId, String recommendIds) {
        Page page = LayuiPageFactory.defaultPage();
        return this.baseMapper.selectByCondition(page, minPrice, maxPrice, condition, memberId, recommendIds);
    }

    /**
     * 获取可挖矿账户
     *
     * @param memberId
     * @return List<Currency>
     */
    public List<ApiMiningCurrencyCoinDto> getMiningCurrency(Long memberId) {
        return finMiningMapper.getNowMiningList(memberId);
    }

    /**
     * 删除币币账户
     */
    public void deleteCurrency(Long currencyId) {
        Currency entity = this.baseMapper.selectById(currencyId);
        //将删除标志设置为Y，表示删除
        entity.setDel("Y");
        this.baseMapper.updateById(entity);
    }

    /**
     * 添加币币账户
     */
    public void addCurrency(Currency currency) {
        this.baseMapper.insert(currency);
    }

    public int updateWallet(Currency entity) {
        if (entity.getUpdateUser() == null)
            entity.setUpdateUser(1L);
        return this.baseMapper.updateWallet(entity);
    }

    public ResponseData edit(Currency wallet) {
        Currency walletQ = this.getById(wallet.getCurrencyId());
        if (walletQ != null) {
            if (!this.updateById(wallet))
                throw new UpdateDataException(100);
            String coin = walletQ.getType();

            if (wallet.getUsedPrice().compareTo(walletQ.getUsedPrice()) > 0) {

                //后台增加
                F.me().saveCashflow(walletQ.getMemberId(), ProConst.WalletBigType.CURRENCY, ProConst.CashFlowOpEnum.FLOW_IN, ProConst.CashFlowTypeEnum.PLATFORM_ADD,
                        wallet.getUsedPrice().subtract(walletQ.getUsedPrice()), coin,
                        wallet.getUsedPrice().subtract(walletQ.getUsedPrice()), coin,
                        BigDecimal.ZERO, coin,
                        ProConst.ItemCode.USED, coin, null, "系统增加",
                        walletQ.getUsedPrice(), wallet.getUsedPrice(), Constant.SYS_PLATFORM, walletQ.getMemberId());

            }
            if (wallet.getUsedPrice().compareTo(walletQ.getUsedPrice()) < 0) {
                //后台减少
                F.me().saveCashflow(walletQ.getMemberId(), ProConst.WalletBigType.CURRENCY, ProConst.CashFlowOpEnum.FLOW_OUT, ProConst.CashFlowTypeEnum.PLATFORM_SUB,
                        walletQ.getUsedPrice().subtract(wallet.getUsedPrice()), coin,
                        walletQ.getUsedPrice().subtract(wallet.getUsedPrice()), coin,
                        BigDecimal.ZERO, coin,
                        ProConst.ItemCode.USED, coin, null, "系统增加",
                        walletQ.getUsedPrice(), wallet.getUsedPrice(), walletQ.getMemberId(), Constant.SYS_PLATFORM);
            }
        }
        return new SuccessResponseData();
    }


    /**
     * 操作币种
     *
     * @return Currency
     */

    public Boolean operateCurrencyUsedPrice(Long memberId, String type, ProConst.CashFlowOpEnum cashFlowOpEnum, BigDecimal price, BigDecimal nowPrice, String remark) {
        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }

        LambdaUpdateWrapper<Currency> luw = new LambdaUpdateWrapper<>();
        luw.eq(Currency::getMemberId, memberId);
        luw.eq(Currency::getType, type);
        luw.eq(Currency::getUsedPrice, nowPrice);

        BigDecimal endPrice;

        if (cashFlowOpEnum == ProConst.CashFlowOpEnum.FLOW_IN) {
            endPrice = nowPrice.add(price);
            luw.set(Currency::getUsedPrice, endPrice);
        } else {

            if (nowPrice.compareTo(price) < 0) {
                return false;
            }

            endPrice = nowPrice.subtract(price);
            luw.set(Currency::getUsedPrice, nowPrice.subtract(price));
        }


        F.me().saveCashflow(memberId, ProConst.WalletBigType.CURRENCY, cashFlowOpEnum, ProConst.CashFlowTypeEnum.TRANSFER_IN,
                price, type, price, type, BigDecimal.ZERO, type,
                ProConst.ItemCode.USED, type, null, remark,
                nowPrice, endPrice,
                null, null);


        return this.update(luw);
    }


    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean operateCurrencyUsedPrice(Long memberId, String type, ProConst.CashFlowOpEnum cashFlowOpEnum, BigDecimal price, String remark) {

        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }

        UpdateWrapper<Currency> wrapper = Wrappers.update();
        if (cashFlowOpEnum == ProConst.CashFlowOpEnum.FLOW_IN) {
            wrapper.setSql(StrUtil.format("used_price = used_price + {}", price));
        } else {
            wrapper.setSql(StrUtil.format("used_price = used_price - {}", price));
        }

        wrapper.eq("member_id", memberId);
        wrapper.eq("type", type);
        if (cashFlowOpEnum != ProConst.CashFlowOpEnum.FLOW_IN) {
            wrapper.apply(StrUtil.format(" used_price - {} >= 0", price));
        }


        F.me().saveCashflow(memberId, ProConst.WalletBigType.CURRENCY, cashFlowOpEnum, ProConst.CashFlowTypeEnum.TRANSFER_IN,
                price, type, price, type, BigDecimal.ZERO, type,
                ProConst.ItemCode.USED, type, null, remark,
                null, null,
                null, null);


        return this.update(wrapper);
    }


    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean operateCurrencyReleasePledgeNum(Long currencyId, ProConst.CashFlowOpEnum cashFlowOpEnum, BigDecimal price, BigDecimal nowPrice) {
        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }

        LambdaUpdateWrapper<Currency> luw = new LambdaUpdateWrapper<>();
        luw.eq(Currency::getCurrencyId, currencyId);
        luw.eq(Currency::getReleasePledgeNum, nowPrice);

        if (cashFlowOpEnum.equals(ProConst.CashFlowOpEnum.FLOW_IN)) {
            luw.set(Currency::getReleasePledgeNum, nowPrice.add(price));
        } else {

            if (nowPrice.compareTo(price) < 0) {
                return false;
            }
            luw.set(Currency::getReleasePledgeNum, nowPrice.subtract(price));
        }

        return this.update(luw);
    }

    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean operateCurrencyReleasePledgeNum(Long memberId, String type,ProConst.CashFlowOpEnum cashFlowOpEnum, BigDecimal price) {
        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }


        UpdateWrapper<Currency> wrapper = Wrappers.update();

        if (cashFlowOpEnum.equals(ProConst.CashFlowOpEnum.FLOW_IN)) {
            wrapper.setSql(StrUtil.format("release_pledge_num = release_pledge_num + {}", price));
        }else {
            wrapper.setSql(StrUtil.format("release_pledge_num = release_pledge_num - {}", price));
        }

        wrapper.eq("member_id", memberId);
        wrapper.eq("type", type);

        return this.update(wrapper);
    }



    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean releaseCurrencyReleasePledgeNum(Long memberId, String type, BigDecimal price, String remark) {


        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }

        UpdateWrapper<Currency> wrapper = Wrappers.update();
        wrapper.setSql(StrUtil.format("used_price = used_price + {}", price));
        wrapper.setSql(StrUtil.format("release_pledge_num = release_pledge_num - {}", price));

        wrapper.eq("member_id", memberId);
        wrapper.eq("type", type);


        F.me().saveCashflow(memberId, ProConst.WalletBigType.CURRENCY, ProConst.CashFlowOpEnum.FLOW_IN, ProConst.CashFlowTypeEnum.TRANSFER_IN,
                price, type, price, type, BigDecimal.ZERO, type,
                ProConst.ItemCode.USED, type, null, remark,
                null, null,
                null, null);


        return this.update(wrapper);
    }



    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean lockCurrencyReleasePledgeNum(Long memberId, String type, BigDecimal price,BigDecimal nowPrice) {


        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }

        UpdateWrapper<Currency> wrapper = Wrappers.update();
        wrapper.setSql(StrUtil.format("locked_price = locked_price + {}", price));
        wrapper.setSql(StrUtil.format("release_pledge_num = release_pledge_num - {}", price));

        wrapper.eq("member_id", memberId);
        wrapper.eq("type", type);
        wrapper.apply(" release_pledge_num = " + nowPrice);

        return this.update(wrapper);
    }

    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean unLockCurrencyReleasePledgeNum(Long memberId, String type, BigDecimal price, String remark) {


        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }

        UpdateWrapper<Currency> wrapper = Wrappers.update();
        wrapper.setSql(StrUtil.format("used_price = used_price + {}", price));
        wrapper.setSql(StrUtil.format("locked_price = locked_price - {}", price));

        wrapper.eq("member_id", memberId);
        wrapper.eq("type", type);


        F.me().saveCashflow(memberId, ProConst.WalletBigType.CURRENCY, ProConst.CashFlowOpEnum.FLOW_IN, ProConst.CashFlowTypeEnum.TRANSFER_IN,
                price, type, price, type, BigDecimal.ZERO, type,
                ProConst.ItemCode.USED, type, null, remark,
                null, null,
                null, null);


        return this.update(wrapper);
    }



    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean lockedCurrencyUsedPrice(Long memberId, String type, BigDecimal price, BigDecimal nowPrice,String remark) {
        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }


        UpdateWrapper<Currency> wrapper = Wrappers.update();
        wrapper.setSql(StrUtil.format("used_price = used_price - {}", price));
        wrapper.setSql(StrUtil.format("locked_price = locked_price + {}", price));
        wrapper.eq("member_id", memberId);
        wrapper.eq("type", type);
        wrapper.apply(StrUtil.format(" used_price - {} >= 0", price));
        wrapper.apply(" used_price = " + nowPrice);

        BigDecimal endPrice = nowPrice.subtract(price);

        F.me().saveCashflow(memberId, ProConst.WalletBigType.CURRENCY, ProConst.CashFlowOpEnum.FLOW_OUT, ProConst.CashFlowTypeEnum.TRANSFER_IN,
                price, type, price, type, BigDecimal.ZERO, type,
                ProConst.ItemCode.USED, type, null, remark,
                nowPrice, endPrice,
                null, null);


        return this.update(wrapper);
    }

    /**
     * 操作币种
     *
     * @return Currency
     */
    public Boolean unLockedCurrencyUsedPrice(Long memberId, String type, BigDecimal price, BigDecimal nowPrice,String remark) {
        if (price.compareTo(BigDecimal.ZERO) < 1) {
            return false;
        }


        UpdateWrapper<Currency> wrapper = Wrappers.update();
        wrapper.setSql(StrUtil.format("locked_price = locked_price - {}", price));
        wrapper.setSql(StrUtil.format("used_price = used_price  + {}", price));
        wrapper.eq("member_id", memberId);
        wrapper.eq("type", type);
        wrapper.apply(StrUtil.format(" locked_price - {} >= 0", price));
        wrapper.apply(StrUtil.format(" used_price = ", nowPrice));

        F.me().saveCashflow(memberId, ProConst.WalletBigType.CURRENCY, ProConst.CashFlowOpEnum.FLOW_OUT, ProConst.CashFlowTypeEnum.TRANSFER_IN,
                price, type, price, type, BigDecimal.ZERO, type,
                ProConst.ItemCode.USED, type, null, remark,
                null, null,
                null, null);


        return this.update(wrapper);
    }


    public BigDecimal getUsedPrice(Long merberId, String type) {
        LambdaQueryWrapper<Currency> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Currency::getMemberId, merberId);
        lqw.eq(Currency::getType, type);
        lqw.select(Currency::getUsedPrice);
        Currency currency = this.getOne(lqw, false);

        if (currency == null) {
            return BigDecimal.ZERO;
        }

        return currency.getUsedPrice();

    }


    public List<Map<String, Object>> getCurrencyList(Long memberId, List<String> currencyIdList) {

        LambdaQueryWrapper<Currency> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Currency::getMemberId, memberId);
        lqw.in(Currency::getType, currencyIdList);
        lqw.select(Currency::getUsedPrice, Currency::getType);
        List<Map<String, Object>> resultList = new ArrayList<>();

        List<Currency> currencies = list(lqw);
        for (Currency currency : currencies) {
            Map<String, Object> map = new HashMap<>();
            map.put("type", currency.getType());
            map.put("num",currency.getUsedPrice() );
            resultList.add(map);
        }


        return resultList;

    }


}
